using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using Caece.Libreria.DNS;
using Caece.Libreria.FrontEnd;
using Caece.Libreria.Protocolo;
using System.Threading;

namespace Caece.Libreria.Manager
{
	class Cliente1
	{
		private string _strDnsIP;
		private int _dnsPort;

		public Cliente1(string dnsIP, int dnsPort)
		{
			_strDnsIP = dnsIP;
			_dnsPort = dnsPort;
		}

		public string ConsultarPorItem(int item)
		{
			clsInfo nodo = GetServidorFrontEnd();
			return this.TalkToFrontEndNode(FrontEndProtocolCommand.ConsultaPorItem, nodo, item.ToString(), CommunicationDirection.Both);
		}

		public string ConsultarPorTema(string tema)
		{
			clsInfo nodo = GetServidorFrontEnd();
			return this.TalkToFrontEndNode(FrontEndProtocolCommand.ConsultaPorTema, nodo, tema, CommunicationDirection.Both);
		}

		public string ComprarItem(int itemId)
		{
			clsInfo nodo = GetServidorFrontEnd();
			return this.TalkToFrontEndNode(FrontEndProtocolCommand.ComprarItem, nodo, itemId.ToString(), CommunicationDirection.Both);
		}

		public void Automatic()
		{
			for (int i = 0; i < 100; i++)
			{
				this.ConsultarPorItem(1);
				this.ComprarItem(1);
				this.ComprarItem(2);				
				this.ConsultarPorTema("autoayuda");
			}
		}

		public void BatchExecution(object op)
		{
			Execution1[] operaciones = (Execution1[])op;
			Execution1 exec = null;

			for (int i = 0; i < operaciones.Length; i++)
			{
				exec = operaciones[i];

				switch (exec.Operacion)
				{
					case Operacion1.ComprarItem:
						this.ComprarItem(Convert.ToInt32(exec.Argument));
						break;
					case Operacion1.ConsultarPorItem:
						this.ConsultarPorItem(Convert.ToInt32(exec.Argument));
						break;
					case Operacion1.ConsultarPorTema:
						this.ConsultarPorTema(exec.Argument);
						break;
				}
			}
		}

		#region Comunicacion con el DNS
		private string TalkToDNS(DNSProtocolCommand cmd, string message)
		{
			Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			IPEndPoint iep = new IPEndPoint(IPAddress.Parse(_strDnsIP), _dnsPort);
			byte[] data = new byte[1024];
			string stringData;

			try
			{
				sock.Connect(iep);

				byte[] sendData = DNSProtocol.Encode(cmd, message);

				sock.Send(sendData, sendData.Length, SocketFlags.None);
				sock.Receive(data);

				DNSProtocol.Decode(data, out stringData);			
			}
			catch (SocketException se)
			{
				Console.WriteLine("SocketException : {0}", se.ToString());
				return null;
			}
			catch (Exception e)
			{
				Console.WriteLine("Exception : {0}", e.ToString());
				return null;
			}
			finally
			{
				sock.Close();
			}
			
			return stringData;
		}
		#endregion

		#region Comunicacion con nodos FrontEnd
		private clsInfo GetServidorFrontEnd()
		{
			clsInfo nodo = DNSProtocol.ResponseDameServidorFronEnd(this.TalkToDNS(DNSProtocolCommand.DameServidorFronEnd, ""));
			return nodo;
		}

		private string TalkToFrontEndNode(FrontEndProtocolCommand cmd, clsInfo nodo, string message, CommunicationDirection direction)
		{
			Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			IPEndPoint iep = new IPEndPoint(IPAddress.Parse(Util.ByteArrayToStr(nodo.Ip)), nodo.Puerto);
			byte[] data = new byte[1024];
			string stringData = "";

			try
			{
				sock.Connect(iep);
				sock.SendTimeout = 1000;

				// Send
				if (direction == CommunicationDirection.Send || direction == CommunicationDirection.Both)
				{
					byte[] sendData = FrontEndProtocol.Encode(cmd, message);
					sock.Send(sendData, sendData.Length, SocketFlags.None);
				}

				// Receive
				if (direction == CommunicationDirection.Receive || direction == CommunicationDirection.Both)
				{
					sock.Receive(data);
					FrontEndProtocol.Decode(data, out stringData);
				}
			}
			catch (SocketException se)
			{
				Console.WriteLine("SocketException : {0}", se.ToString());
				return null;
			}
			catch (Exception e)
			{
				Console.WriteLine("Exception : {0}", e.ToString());
				return null;
			}
			finally
			{
				sock.Close();
			}
			
			return stringData;
		}
		#endregion
	}
}
